<template>
    <div class="rich-text-editor">
        <div style="border: 1px solid; display: flex; flex-direction: column" :style="styles">
            <!-- 如果编辑器实例已创建，则渲染工具栏 -->
            <Toolbar
                v-if="editorRef"
                :editor="editorRef"
                :defaultConfig="defaultToolbarConfig"
                :mode="mode"
                :style="{ 'border-bottom': `1px solid ${props.borderColor}` }"
            />
            <!-- 富文本编辑器核心组件，支持 v-model 双向绑定 -->
            <Editor
                :defaultConfig="editorConfig"
                :mode="mode"
                v-model="modelValueRef"
                style="flex: 1; overflow-y: auto"
                @onCreated="handleCreated"
                @onChange="handleChange"
                @onDestroyed="handleDestroyed"
                @onFocus="handleFocus"
                @onBlur="handleBlur"
            />
        </div>
        <!-- 可选：调试模式下显示原始 HTML（开发时使用，生产环境可移除） -->
        <div v-if="debug" style="margin-top: 10px">
            <h3>原始html：</h3>
            <textarea
                v-model="modelValueRef"
                readonly
                style="width: 100%; outline: none; font-family: monospace"
            ></textarea>
            <!-- 可选：渲染预览 HTML（如用于展示，非编辑时使用） -->
            <h3>预览html：</h3>
            <div class="prose bg-white p-4" v-html="modelValueRef"></div>
        </div>
    </div>
</template>

<script setup lang="ts">
import "@wangeditor-next/editor/dist/css/style.css";

import {
    type IDomEditor,
    type IEditorConfig,
    type ImageElement,
    type IToolbarConfig,
    type VideoElement
} from "@wangeditor-next/editor";
import { Editor, Toolbar } from "@wangeditor-next/editor-for-vue";
import { message } from "ant-design-vue";
import { type CSSProperties, onBeforeUnmount, ref, shallowRef, watch } from "vue";

import { addUnit } from "@/utils/util";

// --- Props（配置项）---
interface Props {
    modelValue: string; // 双向绑定的内容（HTML）
    mode?: "default" | "simple"; // 编辑器模式，默认为完整功能
    height?: string | number;
    width?: string | number;
    borderColor?: string;
    placeholder?: string; // 编辑器占位文本
    debug?: boolean; // 是否显示调试用的原始 HTML 文本框
    // --- 上传配置 ---
    // uploadImageServer?: string; // 图片上传接口地址（默认上传使用）
    // uploadVideoServer?: string; // 视频上传接口地址（默认上传使用）
    maxImageSize?: number; // 图片最大上传大小（单位：MB），默认 5MB
    maxVideoSize?: number; // 视频最大上传大小（单位：MB），默认 100MB
    // 自定义上传函数（优先级高于默认上传）
    customUploadImage?: (
        file: File,
        insertFn: (url: string, alt?: string, href?: string) => void,
        editor: IDomEditor
    ) => Promise<void>;
    customUploadVideo?: (
        file: File,
        insertFn: (url: string, poster?: string) => void,
        editor: IDomEditor
    ) => Promise<void>;
    // --- 工具栏配置 ---
    toolbarConfig?: Partial<IToolbarConfig>; // 自定义工具栏按钮顺序和显示项
    // --- 其他配置 ---
    // [key: string]: any; // 支持传递任意其他配置项到 editorConfig
}

const props = withDefaults(defineProps<Props>(), {
    mode: "default", // 默认使用完整功能模式
    height: "350",
    width: "auto",
    borderColor: "#ccc",
    placeholder: "请输入内容...",
    debug: false,
    maxImageSize: 5, // 默认最大图片 5MB
    maxVideoSize: 100, // 默认最大视频 100MB
    toolbarConfig: () => ({})
    // uploadImageServer, uploadVideoServer, customUploadImage, customUploadVideo, toolbarKeys 可为 undefined
});

// --- Emits（事件）---
const emit = defineEmits<{
    "update:modelValue": [value: string]; // v-model 更新事件
    onChange: [editor: IDomEditor, html: string]; // 编辑内容变化
    onFocus: [editor: IDomEditor]; // 编辑器获得焦点
    onBlur: [editor: IDomEditor]; // 编辑器失去焦点
    onCreated: [editor: IDomEditor]; // 编辑器初始化完成
    onDeletedResources: [urlsToDelete: string[]]; // 发出待删除资源 URL 列表
    // [key: string]: any; // 允许扩展其他自定义事件
}>();

// --- 内部状态 ---
const editorRef = shallowRef<IDomEditor | null>(null); // 编辑器实例，必须用 shallowRef
const modelValueRef = ref(props.modelValue); // 内部绑定的 HTML 内容

const styles = computed<CSSProperties>(() => ({
    height: addUnit(props.height),
    width: addUnit(props.width),
    borderColor: props.borderColor
}));

// 历史插入的图片列表（用于资源清理）
const historyInsertedImageList = ref<ImageElement[]>([]);
// 历史插入的视频列表（用于资源清理）
const historyInsertedVideoList = ref<VideoElement[]>([]);

// 监听父组件传入的 modelValue，同步到内部状态
watch(
    () => props.modelValue,
    newVal => {
        if (newVal !== modelValueRef.value) {
            modelValueRef.value = newVal;
        }
    }
);

// 监听内部内容变化，触发父组件的 update:modelValue 事件
watch(modelValueRef, newVal => {
    if (newVal !== props.modelValue) {
        emit("update:modelValue", newVal);
    }
});

// --- 编辑器配置 ---
const defaultToolbarConfig: Partial<IToolbarConfig> = {
    // 支持通过 props 自定义工具栏按钮
    ...props.toolbarConfig
    // 可在此添加其他工具栏配置项
};

const editorConfig: Partial<IEditorConfig> = {
    placeholder: props.placeholder,
    // 合并所有未被特殊处理的 props 到 editorConfig 中
    ...Object.fromEntries(
        Object.entries(props).filter(
            ([key]) =>
                ![
                    "modelValue",
                    "mode",
                    "placeholder",
                    "debug",
                    "uploadImageServer",
                    "uploadVideoServer",
                    "maxImageSize",
                    "maxVideoSize",
                    "customUploadImage",
                    "customUploadVideo",
                    "toolbarKeys"
                ].includes(key)
        )
    ),
    MENU_CONF: {
        uploadImage: {
            // 小于 5KB 的图片插入为 base64 格式，避免网络请求
            base64LimitSize: 5 * 1024,
            async customUpload(
                file: File,
                insertFn: (url: string, alt?: string, href?: string) => void,
                _editor: IDomEditor
            ) {
                if (!props.customUploadImage) {
                    console.error("RichTextEditor: 请通过 customUploadImage 属性实现图片上传功能！");
                    message.error("图片上传配置错误，请补充自定义上传函数！");
                    return;
                }
                // 校验图片大小
                if (file.size > props.maxImageSize! * 1024 * 1024) {
                    message.error(`图片大小不能超过 ${props.maxImageSize}MB！`);
                    return;
                }

                try {
                    await props.customUploadImage(file, insertFn, _editor);
                } catch (error: any) {
                    console.error("RichTextEditor: 图片上传异常", error);
                    message.error(error.message || "图片上传失败");
                }
            }
        } as any,
        insertImage: {
            // 图片插入后回调，记录非 base64 的网络图片用于后续清理
            onInsertedImage(imageNode: ImageElement | null) {
                if (imageNode == null) return;
                // 只记录网络图片（排除 base64）
                if (!imageNode.src.startsWith("data:image")) {
                    historyInsertedImageList.value.push(imageNode);
                }
            }
        },
        uploadVideo: {
            async customUpload(file: File, insertFn: (url: string, poster?: string) => void, _editor: IDomEditor) {
                if (!props.customUploadVideo) {
                    console.error("RichTextEditor: 请通过 customUploadVideo 属性实现视频上传功能！");
                    message.error("视频上传配置错误，请补充自定义上传函数！");
                    return;
                }
                // 校验视频大小
                if (file.size > props.maxVideoSize! * 1024 * 1024) {
                    message.error(`视频大小不能超过 ${props.maxVideoSize}MB！`);
                    return;
                }
                try {
                    // 如果提供了自定义上传函数，则优先使用
                    await props.customUploadVideo(file, insertFn, _editor);
                } catch (error: any) {
                    console.error("RichTextEditor: 视频上传异常", error);
                    message.error(error.message || "视频上传失败");
                }
            }
        } as any,
        insertVideo: {
            // 视频插入后回调，记录用于后续清理
            onInsertedVideo(videoNode: VideoElement | null) {
                if (videoNode == null) return;
                historyInsertedVideoList.value.push(videoNode);
            }
        } as any
        // 可在此添加更多菜单配置，如链接、表格、代码块等
    }
};

// --- 编辑器回调函数 ---
const handleCreated = (editor: IDomEditor) => {
    editorRef.value = editor; // 保存编辑器实例
    emit("onCreated", editor); // 通知父组件编辑器已创建
};

const handleChange = (editor: IDomEditor) => {
    const html = editor.getHtml(); // 获取当前 HTML 内容
    emit("onChange", editor, html); // 通知父组件内容已变化
};

const handleFocus = (editor: IDomEditor) => {
    emit("onFocus", editor); // 通知父组件编辑器获得焦点
};

const handleBlur = (editor: IDomEditor) => {
    emit("onBlur", editor); // 通知父组件编辑器失去焦点
};

const handleDestroyed = (_editor: IDomEditor) => {
    // 可选：编辑器销毁时记录日志
    // console.log("编辑器已销毁", editor);
};

// --- 组件销毁时清理资源 ---
onBeforeUnmount(() => {
    const editor = editorRef.value;
    if (editor) {
        editor.destroy(); // 销毁编辑器实例，释放内存
        editorRef.value = null; // 清空引用
    }
});

// --- 资源清理函数：删除未在内容中使用的已上传资源 ---
// 该函数由父组件在保存或提交后调用，用于清理冗余文件
const cleanupUnusedResources = async (hostUrl: string) => {
    // 检查编辑器是否已初始化
    if (!editorRef.value || !hostUrl) {
        console.warn("RichTextEditor: 编辑器未初始化或未提供 hostUrl，跳过清理");
        return;
    }

    // 获取当前编辑器中所有的图片元素
    const currentInsertedimageList = editorRef.value.getElemsByType("image") as unknown as ImageElement[];
    const currentInsertedimageSrcList = currentInsertedimageList.map(item => item.src);

    // 找出：曾经上传过、但现在编辑器中已不再引用的图片（且是本域资源）
    const toDelImageList = historyInsertedImageList.value.filter(
        item => item.src.startsWith(hostUrl) && !currentInsertedimageSrcList.includes(item.src)
    );

    // 获取当前编辑器中所有的视频元素
    const currentInsertedVideoList = editorRef.value.getElemsByType("video") as unknown as VideoElement[];
    const currentInsertedVideoSrcList = currentInsertedVideoList.map(item => item.src);

    // 找出：曾经上传过、但现在编辑器中已不再引用的视频（且是本域资源）
    const toDelVideoList = historyInsertedVideoList.value.filter(
        item => item.src.startsWith(hostUrl) && !currentInsertedVideoSrcList.includes(item.src)
    );

    // 合并所有待删除的资源 URL
    const urlsToDelete = [...toDelImageList.map(item => item.src), ...toDelVideoList.map(item => item.src)];

    // 如果有需要清理的资源，通知父组件执行删除操作
    if (urlsToDelete.length > 0) {
        emit("onDeletedResources", urlsToDelete);

        // 如果你希望在组件内部直接调用删除 API，可取消注释以下代码：
        // try {
        //   await Apis.FileAdmin.removeBatchByUrl({
        //     data: { urls: urlsToDelete }
        //   });
        //   // 清理历史记录
        //   historyInsertedImageList.value = historyInsertedImageList.value.filter(item => !urlsToDelete.includes(item.src));
        //   historyInsertedVideoList.value = historyInsertedVideoList.value.filter(item => !urlsToDelete.includes(item.src));
        //   message.success("已清理未使用的上传资源");
        // } catch (error) {
        //   console.error("清理资源失败：", error);
        //   message.error("清理未使用资源失败，请重试");
        // }
    }
};

// --- 暴露方法给父组件 ---
// 通过 defineExpose 让父组件通过 ref 调用此组件的内部方法
defineExpose({
    editorRef, // 编辑器实例（用于调用 API）
    cleanupUnusedResources // 清理冗余资源的公共方法
    // 如需更多功能，可继续暴露：insertText、disable、getHtml 等
});
</script>

<style lang="scss">
.rich-text-editor {
    // 富文本编辑器全屏模式 z-index 设置
    .w-e-full-screen-container {
        z-index: 999;
    }

    // 恢复列表样式（被 Tailwind 清除的默认样式）
    .w-e-text-container [data-slate-editor] ul {
        list-style: disc;
    }
    .w-e-text-container [data-slate-editor] ol {
        list-style: decimal;
    }

    // 恢复标题默认样式
    h1 {
        font-size: 2em;
    }
    h2 {
        font-size: 1.5em;
    }
    h3 {
        font-size: 1.17em;
    }
    h4 {
        font-size: 1em;
    }
    h5 {
        font-size: 0.83em;
    }
    h1,
    h2,
    h3,
    h4,
    h5 {
        font-weight: bold;
    }
}
</style>
